/**
 * WriteXMLOutput.java
 *
 * Enterprise Java
 *
 * Author:  Matthew Braddy
 * Created: Oct 30, 2010
 *
 */

package java113.project.xml;

import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import java.io.*;
import java.util.*;
import java.util.logging.*;
import java113.project.base.Order;
import java113.project.util.DocVsSecurityException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;

/**
 * This class writes an xml file to the filesystem from a collection of Order objects
 *
 * @author Matthew Braddy
 */
public class WriteXMLOutput {

    private Properties  properties;

    private Map         orders;

    private int         counter;

    private Logger      logger;

    private Document    document;

    /**
     * Initialiazation of the class
     *
     * @param properties
     * @param orders
     */
    public WriteXMLOutput(Properties properties, Map orders) {

        setProperties(properties);

        setCounter(0);

        setOrders(orders);

        logger = Logger.getLogger(properties.getProperty("logger"));

        

    }

    /**
     * returns the properties object
     *
     * @return
     */
    public Properties getProperties() {

        return this.properties;

    }

    /**
     * sets the properties object
     *
     * @param properties
     */
    public void setProperties(Properties properties) {

        this.properties = properties;

    }

    /**
     * sets the orders map
     *
     * @param orders
     */
    public void setOrders(Map orders) {

        this.orders = orders;

    }

    /**
     * gets the orders map
     *
     * @return
     */
    public Map getOrders() {

        return this.orders;

    }

    /**
     * gets the counter
     *
     * @return
     */
    public int getCounter() {

        return this.counter;

    }

    /**
     * sets the counter
     *
     * @param counter
     */
    public void setCounter(int counter) {

        this.counter = counter;

    }

    /**
     * gets the document
     *
     * @return the document
     */
    public Document getDocument() {
        return document;
    }

    /**
     *
     * sets the document
     *
     * @param document the document to set
     */
    public void setDocument(Document document) {
        this.document = document;
    }

    /**
     * gets the logger
     *
     * @return the logger
     */
    public Logger getLogger() {
        return logger;
    }

    /**
     *
     * sets the logger
     *
     * @param logger the logger to set
     */
    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    /**
     * this is the controlling method of the class
     *
     */
    public void write() {

        try {

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            setDocument(builder.newDocument());

            String outputFilePath = properties.getProperty("path.output") +
                                   properties.getProperty("xml.file.output");

            createDocument(getDocument());
            writeXML( getDocument(), outputFilePath);

        } catch(Exception Ex) {

            Ex.printStackTrace ();

        }

    }

    /**
     * creates xml document from the map of Order objects
     *
     * @param myDocument
     * @throws DocVsSecurityException
     */
    public void createDocument(Document myDocument) throws DocVsSecurityException {


        if (myDocument == null) {
            throw new DocVsSecurityException(
                    "File contents cannot be empty",
                    DocVsSecurityException.OUTPUT_FAIL, "strIn", myDocument);

        }
            
            Node node, rootNode, orderNode, secondNode;
            
            Iterator i = orders.entrySet().iterator();

            rootNode = getDocument().createElement("report");
            
            while (i.hasNext()) {

                Map.Entry me = (Map.Entry) i.next();
                
                Order order = (Order) me.getValue();

                orderNode = getDocument().createElement("order");

                node = getDocument().createElement("name");
                node.setTextContent(order.getCustomerName());
                orderNode.appendChild(node);

                node = getDocument().createElement("item");

                secondNode = getDocument().createElement("name");
                secondNode.setTextContent(order.getItem());
                node.appendChild(secondNode);
                
                secondNode = getDocument().createElement("quantity");
                secondNode.setTextContent(Integer.toString(order.getQuantity()));
                node.appendChild(secondNode);
                
                secondNode = getDocument().createElement("price");
                secondNode.setTextContent(Double.toString(order.getUnitPrice()));
                node.appendChild(secondNode);
                
                orderNode.appendChild(node);

                node = getDocument().createElement("subTotal");
                node.setTextContent(Double.toString(order.getExtendedPrice()));
                orderNode.appendChild(node);

                node = getDocument().createElement("handlingCharge");
                node.setTextContent(Double.toString(order.getHandlingCharge()));
                orderNode.appendChild(node);

                node = getDocument().createElement("total");
                node.setTextContent(Double.toString(order.getTotal()));
                orderNode.appendChild(node);

                rootNode.appendChild(orderNode);

            }

            myDocument.appendChild(rootNode);
            
    }

    /**
     * Saves created xml to the file system
     *
     * @param oInDoc
     * @param strInPath
     */
    public void writeXML(Document oInDoc, String strInPath) {

        try {

            TransformerFactory transformerFactory =  TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();

            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

            //here we are creating a souce and creating a File reference using our file path in
            //the StreamResult instance; the final transform call streams the document out to the file
            DOMSource oDOMSource = new DOMSource(oInDoc);
            StreamResult oStreamResult = new StreamResult(new File(strInPath));
            transformer.transform(oDOMSource, oStreamResult);

            getLogger().log(Level.INFO, (strInPath +
                    " has been written to the file system."));

        } catch(Exception Ex) {

            Ex.printStackTrace ();

        }

    }

    /**
     * returns a string value of the instance variables
     * 
     * @return
     */
    @Override
    public String toString() {

        return "char contents: " + document.toString() + "\n" +
                "properties: " + properties.toString() + "\n" +
                "orders: " + orders.toString() + "\n" +
                "counter: " + counter + "\n";

    }

}
